﻿package com.saint.video{
	
	import caurina.transitions.Tweener;
	import com.saint.video.data.VideoDataObject;
	import com.saint.video.events.SimpleVideoEvent;
	import com.saint.video.events.VideoEvent;
	import flash.display.Sprite;
	import flash.media.SoundTransform;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.events.NetStatusEvent;
	import flash.media.Video;
	import flash.events.Event;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	
	import com.saint.utils.Logger;
	
	public class SimpleVideo extends Sprite{
		
		private var nc:NetConnection;
		private var video:Video;
		private var ns:NetStream;
		private var videoVolumeTransform:SoundTransform;
		
		private var _reSizeFlv:Boolean;
		private var _stretchToFit:Boolean;
		private var _videoAreaWidth:Number;
		private var _videoAreaHeight:Number;
		private var _videoWidth:Number;
		private var _videoHeight:Number;
		private var _duration:Number;
		private var streamingTimer:Timer;
		
		/**
		 * constructor
		 * creates NetConnection NetStream SoundTransform
		 * creates video object to display video
		 */
		public function SimpleVideo():void {
			nc = new NetConnection();
			nc.connect(null);
			ns = new NetStream(nc);
			
			videoVolumeTransform = new SoundTransform();
			adjustVolume(1);
			
			video = new Video();
			video.attachNetStream(ns);
			video.smoothing = true;
			video.alpha = 0;
			addChild(video);
			
			ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus, false, 0, true);
			ns.client = this;
			
			
			//TODO - remove this - it stops the sounds so i can play TUNES and test
			adjustVolume(0);
		}
		
		/**
		 * sets player values or defaults
		 * @param	data
		 */
		public function initVideo(data:VideoDataObject):void {
			Logger.info("SimpleVideo.initVideo data.videoWidth: " + data.videoWidth)
			data.reSizeFlv			?  	_reSizeFlv = data.reSizeFlv				:   _reSizeFlv	= false;
			data.stretchToFit		?	_stretchToFit =  data.stretchToFit		:	 _stretchToFit = false;
			data.videoAreaWidth		?	_videoAreaWidth = data.videoAreaWidth	:	 _videoAreaWidth = 0;
			data.videoAreaHeight	?	_videoAreaHeight = data.videoAreaHeight	: 	_videoAreaHeight = 0;
			data.videoWidth			?	_videoWidth = data.videoWidth			:	 _videoWidth = 0;
			data.videoHeight		?	_videoHeight = data.videoHeight			:	 _videoHeight = 0;
			//drawBg();
		}
		
		/**
		 * play a video file (starts PlayBack);
		 * starts timer / listener to measure streaming
		 * @param	filename
		 */
		public function playVideo(filename:String):void {
			ns.play(filename);
			streamingTimer = new Timer(100);
			streamingTimer.addEventListener(TimerEvent.TIMER, checkBytesLoaded, false, 0, true);
			streamingTimer.start();
		}
		
		/**
		 * pause netstream
		 */
		public function pauseVideo():void {
			Logger.info("SimpleVideo.pauseVideo");
			ns.pause();
		}
		
		/**
		 * restart paused netsream
		 */
		public function resumeVideo():void {
			Logger.info("SimpleVideo.resumeVideo");
			ns.resume();
		}
		
		/**
		 * moves current viewing position within the netstream
		 * @param	percentage
		 */
		public function seek(percentage:Number):void {
			Logger.info("\nSimpleVideo.seek " + percentage);
			Logger.info("SimpleVideo.seek _duration" + _duration);
			var newTime:Number = (_duration / 100) * percentage;
			Logger.info("SimpleVideo.seek Math.round(newTime)" + Math.round(newTime));
			ns.seek(Math.round(newTime));
		}
		
		/**
		 * change the volume of the netstream in range 0-1
		 * @param	vol
		 */
		public function adjustVolume(vol:Number):void {
			Logger.info("simplevideo vol:" + vol );
			videoVolumeTransform.volume = vol;
			ns.soundTransform = videoVolumeTransform;
		}
		
		
		
		/**
		 * reset
		 * 
		 * removes listeners ans stops timers
		 */
		public function reset():void
		{
			Logger.info("simpleVideo.reset");
			
			//remove previous listeners and stop timers
			try
			{
				streamingTimer.stop();
				streamingTimer.removeEventListener(TimerEvent.TIMER, checkBytesLoaded);
				streamingTimer = null
			}
			catch (e:Error)
			{
				Logger.error("simpleVideo.reset - Error destroying streamingTimer");
			}
		}	
		
		
		
		
		/**
		 * sizes the video:
		 * 
		 * 
		 *      reSizeFlv = true:  video will use be resized 
		 * 		reSizeFlv = false: video will use flv 'natural dimensions
		 * 
		 * 		strechToFill = true: video will stretch (and distort) to fill whole availabele area
		 * 		strechToFill = false:
		 * 
		 *	 	compare the shape of the video compared to the video display area as we can tell whether to use maxHeight ot max width as the size 
		 * 		to scale the video up to
		 * 
		 * @param	w
		 * @param	h
		 */
		private function sizeVideo(w:Number, h:Number):void {
			Logger.info("SimpleVideo.sizeVideo _stretchToFit: " + _stretchToFit)
			
			var vidWidth:Number;
			var vidHeight:Number;
			
			if(!_reSizeFlv){
				vidWidth = w;
				vidHeight = h;
			}else {
				// size to fit
				if (_stretchToFit)
				{
					vidWidth = _videoAreaWidth;
					vidHeight = _videoAreaHeight;
				}
				else 
				{
					var flvRatio:Number = w / h;
					var areaRatio:Number = _videoAreaWidth / _videoAreaHeight;
					
					
					Logger.info("SimpleVideo.sizeVideo flvRatio: " + flvRatio + ", areaRatio: " + areaRatio);
					
					if (areaRatio < flvRatio)
					{
						Logger.info("SimpleVideo.sizeVideo areaRatio < flvRatio");
						vidWidth = _videoAreaWidth;
						vidHeight = _videoAreaWidth * (h/w);						
					}
					else
					{
						Logger.info("SimpleVideo.sizeVideo areaRatio > flvRatio");
						vidHeight = _videoAreaHeight;							
						vidWidth = _videoAreaHeight * flvRatio;
					}					
				}
			}
			
			video.width = vidWidth;
			video.height = vidHeight;
			
			//TODO - cath this resize event and resize the controls
			dispatchEvent(new SimpleVideoEvent(SimpleVideoEvent.RESIZE, videoWidth, vidHeight));
		}
		
	
		
		
		/**
		 * centers the videa within the available area
		 * @TODO - allow horizontal OR vertical
		 */
		private function centreVideo():void {
			video.x = (videoAreaWidth - video.width) / 2;
		}
		
		/**
		 * utility to draw black background to fill video area around actual video size
		 */
		private function drawBg():void {
			graphics.beginFill(0x000000);
			graphics.drawRect(0, 0, videoAreaWidth, videoAreaHeight);
			graphics.endFill();
		}
		
		
		
/**
 * LISTENERS
 */
		/**
		 * checks loading of current netstream
		 * @param	event
		 */
		private function checkBytesLoaded(event:TimerEvent):void {
			var percentageLoaded:Number = ns.bytesLoaded / ns.bytesTotal;
			Logger.info("SimpleVideo.checkBytesLoaded : " + (percentageLoaded * 100) + "%");
			dispatchEvent(new VideoEvent(VideoEvent.STREAMING_PECENTAGE, percentageLoaded));
			if (percentageLoaded >= 1) {
				streamingTimer.stop();
			}
		}
		
		/**
		 * handle NetStatus events
		 * @param	event
		 */
		private function onNetStatus(event:NetStatusEvent):void {
			var info:Object = event.info;
			Logger.info("Net status received:" + info.code);
			if (info.code == "NetStream.Play.Stop") {
				//seek(0);
				dispatchEvent(new VideoEvent(VideoEvent.PLAY_STOPPED));
				Tweener.addTween(video, { alpha:0, time:1 } );
			}
		}
		
		/**
		 * pull out all metadata properties
		 * @param	info
		 */
		public function onMetaData(info:Object):void {
			Logger.info("simpleVideo.onMetaData");
			sizeVideo(info.width, info.height);
			Tweener.addTween(video, { alpha:1, time:1 } );
			_duration = info.duration;
			dispatchEvent(new VideoEvent(VideoEvent.META_DATA_DURATION, _duration));
			
			//for (var prop in info) {
				//Logger.info("metadata: " + prop + " is " + info[prop]);
			//}
		}

		
/**
 * GETTERS AND SETTERS
 */
		public function get reSizeFlv():Boolean {
			return _reSizeFlv;
		}
		
		public function get videoWidth():Number {
			return _videoWidth;
		}
		
		public function get videoHeight():Number {
			return _videoHeight;
		}
		
		public function get videoAreaWidth():Number {
			return _videoAreaWidth;
		}
		
		public function get videoAreaHeight():Number {
			return _videoAreaHeight;
		}
		
		public function get currentTime():Number {
			return ns.time;
		}
		
	}
}